package logic

import (
	"context"
	"strings"
	"time"

	"mall/common/enumx"
	"mall/common/modelx"
	"mall/common/resultx"
	"mall/service/blog/model"
	"mall/service/blog/rpc/internal/svc"
	"mall/service/blog/rpc/types/blog"

	"github.com/zeromicro/go-zero/core/logx"
)

type BookListLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewBookListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BookListLogic {
	return &BookListLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *BookListLogic) BookList(in *blog.BookListReq) (*blog.BookListResp, error) {
	logx.Infof("BookListReq: %+v ", in)
	// Limit:10  Preload:\"blogBook:Id,Title,Slug,CommentCount,year;blogMedia:Id,Uid,Url,Thumbnail;blogBookRelation:brand\"  EagerLoad:\"blogBook:blogMedia,blogBookRelation\"  EntryIds:\"40046\"  Search:\"a\"  PreFilterEntity:\"blogTerm\"  PreFilter:\"Slug,equalTo:perfumes;Taxonomy,equalTo:11\"  VisitorId:10002  PlatformId:1

	if in.Preload == "" && in.EagerLoad == "" {
		return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
	}

	preloadMap, eagerLoadMap := modelx.GetPreloadMap(in.Preload, in.EagerLoad)
	logx.Infof("preloadMap: %+v ", preloadMap)
	// preloadMap: map[blogBook:[Id Title Slug CommentCount year] blogBookRelation:[brand] blogMedia:[Id Uid Url Thumbnail]]
	logx.Infof("eagerLoadMap: %+v ", eagerLoadMap)
	// eagerLoadMap: map[blogBook:[blogMedia blogBookRelation]]

	blogBookEntityName := model.RpcEntityNames.BlogBook
	_, hasSettingMap := model.RpcEntityPreloadMap[blogBookEntityName] // BlogKnowledgeBasis的关联字段
	if !hasSettingMap {
		return &blog.BookListResp{}, nil
	}

	blogBookRepositoryName := model.RepositoryNames.BlogBook
	columnMap, hasColumnMap := model.RepositoryPreloadMap[blogBookRepositoryName] // BlogKnowledgeBasis的数据库字段
	if !hasColumnMap {
		return &blog.BookListResp{}, nil
	}

	blogBookRelationEntityName := model.RpcEntityNames.BlogBookRelation
	blogBookRelationSettingMap, hasBlogBookRelationSettingMap := model.RpcEntityPreloadMap[blogBookRelationEntityName]
	if !hasBlogBookRelationSettingMap {
		return &blog.BookListResp{}, nil
	}

	var sectionIds []any
	sectionMap := make(map[uint64]string) // 记录 BlogBookRelation 的全部 section name
	for _, s := range blogBookRelationSettingMap {
		if s.Id > 0 {
			if _, exist := sectionMap[s.Id]; !exist {
				sectionMap[s.Id] = s.Name
				sectionIds = append(sectionIds, s.Id)
			}
		}
	}

	// 解析 preload 的字段
	var selectCols []string
	if preloadFields, hasPreloadFields := preloadMap[blogBookEntityName]; hasPreloadFields {
		selectColMap := make(map[string]string)
		for _, field := range preloadFields {
			if _, exist := selectColMap[field]; !exist {
				if column, hasColumn := columnMap[field]; hasColumn {
					selectColMap[field] = column
				} else {
					selectColMap[field] = ""
				}
			}
		}
		for _, column := range selectColMap {
			if column != "" {
				selectCols = append(selectCols, column)
			}
		}
	}

	// 额外的offset
	var offset int32
	var count int64
	var err error
	var oidMap map[uint64]int16

	var searchStr string
	if in.Search != "" {
		searchStr = in.Search
	} else if in.Title != "" {
		searchStr = in.Title
	} else if in.Slug != "" {
		searchStr = in.Slug
	}
	selectStr := strings.Join(selectCols, ",")

	idStickyMap := make(map[uint64]int16) // Map: model.BlogTermRelationship.ObjectID => model.BlogTermRelationship.StickyType
	var entryList []*model.BlogKnowledgeBasis

	if in.EntryIds != "" { // 根据ID获取
		filterMap := make(map[string]map[string][]any)
		filterMap[model.BlogKnowledgeBasisColumns.ID] = map[string][]any{
			"in": modelx.UniqueValues(strings.Split(in.EntryIds, ","), 64),
		}
		filterMap[model.BlogKnowledgeBasisColumns.PostStatus] = map[string][]any{
			"equalTo": []any{enumx.PostStatusPublish},
		}

		entryList, _, err = l.svcCtx.BlogBook.GetList(l.ctx, model.M{
			"orderBy": model.BlogKnowledgeBasisColumns.ID + " DESC",
			"select": selectStr,
		}, -1, filterMap)
		if err != nil {
			return nil, err
		}
	} else if in.PreFilterEntity != "" && in.PreFilter != "" {
		blogTermEntityName := model.RpcEntityNames.BlogTerm
		blogTermRepositoryName := model.RepositoryNames.BlogTerm
		if blogTermEntityName == in.PreFilterEntity {
			_, hasBlogTermSettingMap := model.RpcEntityPreloadMap[blogTermEntityName]
			blogTermColumnMap, hasBlogTermColumnMap := model.RepositoryPreloadMap[blogTermRepositoryName]
			if hasBlogTermSettingMap && hasBlogTermColumnMap {
				var preFilterMap map[string]map[string][]any
				preFilterMap = modelx.GetFilterMap(in.PreFilter, blogTermColumnMap)
				logx.Infof("blogTerm FilterMap: %+v ", preFilterMap)
				// blogTerm FilterMap: map[slug:map[equalTo:[perfumes]] taxonomy:map[equalTo:[11]]]
				var pageSize int64 = 1
				termList, _, err := l.svcCtx.BlogTerm.GetList(l.ctx, model.M{
					"pageSize": pageSize,
					"select":   ",",
				}, -1, preFilterMap)
				if err != nil { // 找不到分类
					return nil, err
				}

				if len(termList) > 0 {
					var filterMap map[string]map[string][]any
					if in.Filter != "" {
						filterMap = modelx.GetFilterMap(in.Filter, columnMap)
						logx.Infof("filterMap: %+v ", filterMap)
						// filterMap: 
					}
					if filterMap == nil {
						filterMap = make(map[string]map[string][]any)
					}
					filterMap[model.BlogTermRelationshipColumns.TermID] = map[string][]any{
						"equalTo": []any{termList[0].TermID},
					}
					filterMap[model.BlogTermRelationshipColumns.ObjectType] = map[string][]any{
						"equalTo": []any{enumx.PostTypeKnowledgeBase},
					}
					// logx.Infof("blogTermRelationship FilterMap: %+v ", filterMap)
					// blogTermRelationship FilterMap: map[object_type:map[equalTo:[141]] term_id:map[equalTo:[15]]]

					subFilterMap := make(map[string]map[string][]any)
					var cnt int32
					for {
						offset = in.Limit * cnt
						cnt += 1
						oidMap, count, err = l.preFilterByTermId(filterMap, in.Offset + offset, in.Limit)
						if err != nil {
							return nil, err
						}

						var oids []any // []model.BlogTermRelationship.ObjectID(已去重)
						for k, v := range oidMap {
							oids = append(oids, k)
							idStickyMap[k] = v
						}

						if len(oids) == 0 { // 没有记录
							break
						}

						subFilterMap[model.BlogKnowledgeBasisColumns.ID] = map[string][]any{
							"in": oids,
						}
						subFilterMap[model.BlogKnowledgeBasisColumns.PostStatus] = map[string][]any{
							"equalTo": []any{enumx.PostStatusPublish},
						}
						tmpList, tmpErr := l.filterByIds(subFilterMap, searchStr, selectStr)
						if tmpErr != nil {
							return nil, tmpErr
						}

						for _, tmp := range tmpList {
							entryList = append(entryList, tmp)
						}

						if len(entryList) >= int(in.Limit) { // 已有足够的记录数
							break
						}

						if count <= 1 { // 没有下一页了
							break
						}
					}
				}
			}
		}
	} else if searchStr != "" { // 根据searchStr获取
		filterMap := make(map[string]map[string][]any)
		filterMap[model.BlogKnowledgeBasisColumns.PostStatus] = map[string][]any{
			"equalTo": []any{enumx.PostStatusPublish},
		}

		var cnt int32
		var eids []any // []model.BlogKnowledgeBasis.ID(已去重)
		oidMap := make(map[uint64]int) // Map: model.BlogKnowledgeBasis.ID => int
		for {
			offset = in.Limit * cnt
			cnt += 1
			var tmpList []*model.BlogKnowledgeBasis
			var tmpErr error
			tmpList, count, tmpErr = l.svcCtx.BlogBook.GetList(l.ctx, model.M{
				"offset":  in.Offset + offset,
				"limit":   in.Limit,
				"orderBy": model.BlogKnowledgeBasisColumns.ID + " DESC",
				"search":  searchStr,
				"select":  model.BlogKnowledgeBasisColumns.ID,
			}, 3, filterMap)
			if tmpErr != nil {
				return nil, tmpErr
			}

			if len(tmpList) == 0 { // 没有记录
				break
			}

			var oids []any // []model.BlogTermRelationship.ObjectID(已去重)
			for i, tmp := range tmpList {
				if _, exist := oidMap[tmp.ID]; !exist {
					oids = append(oids, tmp.ID)
					oidMap[tmp.ID] = i
				}
			}

			if len(oids) == 0 { // 没有新记录
				continue
			}

			var subFilterMap map[string]map[string][]any
			if in.Filter != "" {
				subFilterMap = modelx.GetFilterMap(in.Filter, columnMap)
				logx.Infof("blogTermRelationship filterMap: %+v ", filterMap)
				// blogTermRelationship filterMap: 
			}
			if subFilterMap == nil {
				subFilterMap = make(map[string]map[string][]any)
			}

			subFilterMap[model.BlogTermRelationshipColumns.ObjectID] = map[string][]any{
				"in": oids,
			}
			subFilterMap[model.BlogTermRelationshipColumns.TermID] = map[string][]any{
				"in": sectionIds,
			}
			relationList, _, listErr := l.svcCtx.BlogTerm.GetRelationshipList(l.ctx, model.M{
				"orderBy": model.BlogTermRelationshipColumns.ObjectID + " DESC",
				"select":  model.BlogTermRelationshipColumns.ObjectID + "," + model.BlogTermRelationshipColumns.StickyType,
			}, -1, subFilterMap)
			if listErr != nil {
				return nil, listErr
			}

			if len(relationList) == 0 { // 没有新记录
				continue
			}

			for _, relationship := range relationList {
				eids = append(eids, relationship.ObjectID)
				idStickyMap[relationship.ObjectID] = relationship.StickyType
			}

			if len(eids) >= int(in.Limit) { // 已有足够的记录数
				break
			}

			if count <= 1 { // 没有下一页
				break
			}
		}

		if len(eids) > 0 {
			filterMap[model.BlogKnowledgeBasisColumns.ID] = map[string][]any{
				"in": eids,
			}
			entryList, _, err = l.svcCtx.BlogBook.GetList(l.ctx, model.M{
				"orderBy": model.BlogKnowledgeBasisColumns.ID + " DESC",
				"select":  selectStr,
			}, -1, filterMap)
			if err != nil {
				return nil, err
			}
		}
	}

	var entries []*blog.BookDetailResp
	var searchLogId int64
	if len(entryList) > 0 {
		if in.VisitorId > 0 && in.PlatformId > 0 && searchStr != "" {
			searchLogId = l.svcCtx.BlogUser.InsertSearchLog(l.ctx, &model.BlogUserSearchLog{
				UserID:     uint64(in.VisitorId),
				PlatformID: uint(in.PlatformId),
				Keyword:    searchStr,
				Status:     uint8(enumx.ObjectStatusAproved),
				CreatedAt:  time.Now(),
			})
		}

		var ids []any // []model.BlogKnowledgeBasis.ID
		for _, entry := range entryList {
			ids = append(ids, entry.ID)
		}

		subEntitySettingMap := make(map[string]map[string]*model.ColumnSetting)
		if eagerLoadEntities, hasEagerLoadEntities := eagerLoadMap[blogBookEntityName]; hasEagerLoadEntities {
			for _, entity := range eagerLoadEntities {
				if entitySettingMap, hasEntitySettingMap := model.RpcEntityPreloadMap[entity]; hasEntitySettingMap {
					subEntitySettingMap[entity] = entitySettingMap
				}
			}
		}

		idCategoryMap := make(map[uint64][]*blog.BlogCategory) // Map: model.BlogKnowledgeBasis.ID => []*blog.BlogCategory
		idTagMap := make(map[uint64][]*blog.BlogTag) // Map: model.BlogKnowledgeBasis.ID => []*blog.BlogTag
		idSectionMap := make(map[uint64][]*blog.BlogCategory) // Map: model.BlogKnowledgeBasis.ID => []*blog.BlogCategory
		blogTermEntityName := model.RpcEntityNames.BlogTerm
		blogTermRepositoryName := model.RepositoryNames.BlogTerm
		if _, hasEntitySettingMap := subEntitySettingMap[blogTermEntityName]; hasEntitySettingMap {
			subPreloadFields, hasSubPreloadFields := preloadMap[blogTermEntityName]
			subColumnMap, hasSubColumnMap := model.RepositoryPreloadMap[blogTermRepositoryName]
			if hasSubPreloadFields && hasSubColumnMap {
				subFilterMap := make(map[string]map[string][]any)
				subFilterMap[model.BlogTermRelationshipColumns.ObjectID] = map[string][]any{
					"in": ids,
				}
				subFilterMap[model.BlogTermRelationshipColumns.ObjectType] = map[string][]any{
					"equalTo": []any{enumx.PostTypeKnowledgeBase},
				}
				relationList, _, listErr := l.svcCtx.BlogTerm.GetRelationshipList(l.ctx, model.M{}, -1, subFilterMap)
				if listErr != nil {
					return nil, listErr
				}

				if len(relationList) > 0 {
					selectColMap := make(map[string]string)
					for _, field := range subPreloadFields {
						if _, exist := selectColMap[field]; !exist {
							if column, hasColumn := subColumnMap[field]; hasColumn {
								selectColMap[field] = column
							} else {
								selectColMap[field] = ""
							}
						}
					}
					var subSelectCols []string
					for _, column := range selectColMap {
						if column != "" {
							subSelectCols = append(subSelectCols, column)
						}
					}

					tidMap := make(map[uint64][]uint64) // Map: model.BlogTerm.TermID => []model.BlogKnowledgeBasis.ID
					var tids []any // []model.BlogTerm.TermID(已去重)
					for _, relationship := range relationList {
						if _, exist := tidMap[relationship.TermID]; !exist {
							tids = append(tids, relationship.TermID)
						}
						tidMap[relationship.TermID] = append(tidMap[relationship.TermID], relationship.ObjectID)
					}

					termFilterMap := make(map[string]map[string][]any)
					termFilterMap[model.BlogTermColumns.TermID] = map[string][]any{
						"in": tids,
					}
					termList, _, listErr := l.svcCtx.BlogTerm.GetList(l.ctx, model.M{
						"select": strings.Join(subSelectCols, ","),
					}, -1, termFilterMap)
					if listErr != nil {
						return nil, listErr
					}

					if len(termList) > 0 {
						for _, term := range termList {
							if oids, ok := tidMap[term.TermID]; ok {
								switch enumx.TermTaxonomy(term.Taxonomy) {
								case enumx.TermTaxonomyCategory:
									oidMap := make(map[uint64]struct{})
									for _, oid := range oids {
										if _, ok := oidMap[oid]; !ok {
											idCategoryMap[oid] = append(idCategoryMap[oid], &blog.BlogCategory{
												Id:   int64(term.TermID),
												Name: term.Name,
												Slug: term.Slug,
											})
											oidMap[oid] = struct{}{}
										}
									}
								case enumx.TermTaxonomyTag:
									oidMap := make(map[uint64]struct{})
									for _, oid := range oids {
										if _, ok := oidMap[oid]; !ok {
											idTagMap[oid] = append(idTagMap[oid], &blog.BlogTag{
												Id:   int64(term.TermID),
												Name: term.Name,
												Slug: term.Slug,
											})
											oidMap[oid] = struct{}{}
										}
									}
								case enumx.TermTaxonomyKnowledgeBase:
									var alias string
									if s, ok := sectionMap[term.TermID]; ok {
										alias = s
									}
									oidMap := make(map[uint64]struct{})
									for _, oid := range oids {
										if _, ok := oidMap[oid]; !ok {
											idSectionMap[oid] = append(idSectionMap[oid], &blog.BlogCategory{
												Id:   int64(term.TermID),
												Name: term.Name,
												Slug: term.Slug,
												Uri:  alias,
											})
											oidMap[oid] = struct{}{}
										}
									}
								}
							}
						}
					}
				}
			}
		}

		idMediaMap := make(map[uint64][]*blog.BlogMedia) // Map: model.BlogKnowledgeBasis.ID => *blog.BlogMedia
		blogMediaEntityName := model.RpcEntityNames.BlogMedia
		blogMediaRepositoryName := model.RepositoryNames.BlogMedia
		if _, hasEntitySettingMap := subEntitySettingMap[blogMediaEntityName]; hasEntitySettingMap {
			subPreloadFields, hasSubPreloadFields := preloadMap[blogMediaEntityName]
			subColumnMap, hasSubColumnMap := model.RepositoryPreloadMap[blogMediaRepositoryName]
			if hasSubPreloadFields && hasSubColumnMap {
				selectColMap := make(map[string]string)
				for _, field := range subPreloadFields {
					if _, exist := selectColMap[field]; !exist {
						if column, hasColumn := subColumnMap[field]; hasColumn {
							selectColMap[field] = column
						} else {
							selectColMap[field] = ""
						}
					}
				}
				var subSelectCols []string
				for _, column := range selectColMap {
					if column != "" {
						subSelectCols = append(subSelectCols, column)
					}
				}
				mediaFilterMap := make(map[string]map[string][]any)
				mediaFilterMap[model.BlogAttachmentRelationshipColumns.ObjectID] = map[string][]any{
					"in": ids,
				}
				mediaFilterMap[model.BlogAttachmentRelationshipColumns.ObjectType] = map[string][]any{
					"equalTo": []any{enumx.PostTypeKnowledgeBase},
				}
				mediaFilterMap[model.BlogAttachmentRelationshipColumns.AttachmentThumbnail] = map[string][]any{
					"equalTo": []any{1},
				}
				mediaList, _, listErr := l.svcCtx.BlogBook.GetMedia(l.ctx, model.M{
					"orderBy": model.BlogAttachmentRelationshipColumns.AttachmentOrder,
					"select": strings.Join(subSelectCols, ","),
				}, -1, mediaFilterMap) // 读取关联表
				if listErr != nil {
					return nil, listErr
				}

				if len(mediaList) > 0 {
					for _, media := range mediaList {
						idMediaMap[media.ObjectID] = append(idMediaMap[media.ObjectID], &blog.BlogMedia{
							Uid:       int64(media.AttachmentRelationshipID),
							Id:        int64(media.AttachmentID),
							Uri:       media.AttachmentSource,
							Thumbnail: int32(media.AttachmentThumbnail),
							Order:     int32(media.AttachmentOrder),
							Url:       media.AttachmentImageURL,
							AltText:   media.AttachmentImageAlt,
							Meta:      media.AttachmentImageMeta,
						})
					}
				}
			}
		}

		idMetaMap := make(map[uint64][]*blog.BlogMeta) // Map: model.BlogKnowledgeBasis.ID => *blog.BlogMeta
		blogBookMetaEntityName := model.RpcEntityNames.BlogBookMeta
		if entitySettingMap, hasEntitySettingMap := subEntitySettingMap[blogBookMetaEntityName]; hasEntitySettingMap {
			if subPreloadFields, hasSubPreloadFields := preloadMap[blogBookMetaEntityName]; hasSubPreloadFields {
				var metaKeys []any
				metaKeyMap := make(map[string]string)
				for _, field := range subPreloadFields {
					fieldSetting, hasFieldSetting := entitySettingMap[field]
					if hasFieldSetting && fieldSetting.Name != "" {
						metaKeys = append(metaKeys, fieldSetting.Name)
						metaKeyMap[fieldSetting.Name] = field
					}
				}
				if len(metaKeys) > 0 {
					metaFilterMap := make(map[string]map[string][]any)
					metaFilterMap[model.BlogKnowledgeBaseMetumColumns.KnowledgeBaseID] = map[string][]any{
						"in": ids,
					}
					metaFilterMap[model.BlogKnowledgeBaseMetumColumns.MetaKey] = map[string][]any{
						"in": metaKeys,
					}
					metaList, _, listErr := l.svcCtx.BlogBook.GetMeta(l.ctx, model.M{}, -1, metaFilterMap)
					if listErr != nil {
						return nil, listErr
					}

					if len(metaList) > 0 {
						for _, metum := range metaList {
							if metum.MetaKey != "" && metum.MetaValue.Valid {
								if field, hasField := metaKeyMap[metum.MetaKey]; hasField {
									idMetaMap[metum.KnowledgeBaseID] = append(idMetaMap[metum.KnowledgeBaseID], &blog.BlogMeta{
										Id: int64(metum.MetaID),
										Key: field,
										Value: metum.MetaValue.String,
									})
								}
							}
						}
					}
				}
			}
		}

		idEntriesMap := make(map[uint64][]*blog.BlogEntry) // Map: model.BlogKnowledgeBasis.ID => []*blog.BlogEntry
		blogBookRelationRepositoryName := model.RepositoryNames.BlogBookRelation
		if _, hasEntitySettingMap := subEntitySettingMap[blogBookRelationEntityName]; hasEntitySettingMap {
			subPreloadFields, hasSubPreloadFields := preloadMap[blogBookRelationEntityName]
			subColumnMap, hasSubColumnMap := model.RepositoryPreloadMap[blogBookRelationRepositoryName]
			if hasSubPreloadFields && hasSubColumnMap {
				preloadMap := make(map[string]int)
				selectColMap := make(map[string]string)
				for idx, field := range subPreloadFields {
					if _, exist := preloadMap[field]; !exist { // 确定relation的key及entry的字段
						preloadMap[field] = idx
						if column, hasColumn := subColumnMap[field]; hasColumn {
							selectColMap[field] = column
						} else {
							selectColMap[field] = ""
						}
					}
				}

				var relationIds []any
				for _, s := range blogBookRelationSettingMap {
					if s.Id > 0 {
						if _, exist := preloadMap[s.Name]; exist {
							relationIds = append(relationIds, s.Id)
						}
					}
				}
				if len(relationIds) > 0 { // relation 的 section id 数组不为空
					var subSelectCols []string
					for _, column := range selectColMap {
						if column != "" {
							subSelectCols = append(subSelectCols, column)
						}
					}

					var relationList []*model.BlogKnowledgeBaseRelationship
					var listErr error
					relationFilterMap := make(map[string]map[string][]any)
					relationFilterMap[model.BlogKnowledgeBaseRelationshipColumns.FromEntryID] = map[string][]any{
						"in": ids,
					}
					relationFilterMap[model.BlogKnowledgeBaseRelationshipColumns.ToSectionID] = map[string][]any{
						"in": relationIds,
					}
					relationSelectCols := []string{
						model.BlogKnowledgeBaseRelationshipColumns.FromEntryID,
						model.BlogKnowledgeBaseRelationshipColumns.ToEntryID,
						model.BlogKnowledgeBaseRelationshipColumns.ToSectionID,
						model.BlogKnowledgeBaseRelationshipColumns.ToEntryGroup,
						model.BlogKnowledgeBaseRelationshipColumns.ToEntryOrder,
						model.BlogKnowledgeBaseRelationshipColumns.ToEntryMeta,
					}
					relationList, _, listErr = l.svcCtx.BlogBook.GetRelationshipList(l.ctx, model.M{
						"select":  strings.Join(relationSelectCols, ","),
						"orderBy": model.BlogKnowledgeBaseRelationshipColumns.ToEntryOrder,
					}, -1, relationFilterMap)
					if listErr != nil {
						return nil, listErr
					}

					if len(relationList) > 0 {
						idRelationMap := make(map[uint64][]*model.BlogKnowledgeBaseRelationship)
						tidMap := make(map[uint64]int) // tids 去重 Map: model.BlogKnowledgeBasis.ID => int
						var tids []any
						for idx, relationship := range relationList {
							idRelationMap[relationship.FromEntryID] = append(idRelationMap[relationship.FromEntryID], relationship)
							if _, exist := tidMap[relationship.ToEntryID]; !exist {
								tidMap[relationship.ToEntryID] = idx
								tids = append(tids, relationship.ToEntryID)
							}
						}
						if len(tids) > 0 {
							entryFilterMap := make(map[string]map[string][]any)
							entryFilterMap[model.BlogKnowledgeBasisColumns.ID] = map[string][]any{
								"in": tids,
							}
							entryFilterMap[model.BlogKnowledgeBasisColumns.PostStatus] = map[string][]any{
								"equalTo": []any{enumx.PostStatusPublish},
							}
							var entrySelectCols []string
							if len(subSelectCols) > 0 {
								entrySelectCols = subSelectCols[:]
							} else {
								entrySelectCols = []string{
									model.BlogKnowledgeBasisColumns.ID,
									model.BlogKnowledgeBasisColumns.PostTitle,
									model.BlogKnowledgeBasisColumns.PostName,
									model.BlogKnowledgeBasisColumns.GUID,
								}
							}
							relationEntryList, _, err := l.svcCtx.BlogBook.GetList(l.ctx, model.M{
								"select": strings.Join(entrySelectCols, ","),
							}, -1, entryFilterMap)
							if err != nil {
								return nil, err
							}

							relationEntryMap := make(map[uint64]*model.BlogKnowledgeBasis)
							for _, e := range relationEntryList {
								relationEntryMap[e.ID] = e
							}
							for id, rs := range idRelationMap {
								entryMap := make(map[uint64]int) // Map: model.BlogKnowledgeBasis.ID => int
								for i, r := range rs {
									if _, exist := entryMap[r.ToEntryID]; exist {
										continue
									}

									entryMap[r.ToEntryID] = i
									if e, exist := relationEntryMap[r.ToEntryID]; exist {
										var section string
										if s, ok := sectionMap[r.ToSectionID]; ok {
											section = s
										}
										idEntriesMap[id] = append(idEntriesMap[id], &blog.BlogEntry{
											Id:        int64(e.ID),
											Title:     e.PostTitle,
											Slug:      e.PostName,
											Link:      e.GUID,
											SectionId: int64(r.ToSectionID),
											Section:   section,
											GroupId:   int64(r.ToEntryGroup),
											Order:     int64(r.ToEntryOrder),
										})
									}
								}
							}
						}
					}
				}
			}
		}

		idDetailMap := make(map[uint64]string) // Map: model.BlogKnowledgeBasis.ID => string
		blogDetailEntityName := model.RpcEntityNames.BlogBookDetail
		blogDetailRepositoryName := model.RepositoryNames.BlogBookDetail
		if _, hasEntitySettingMap := subEntitySettingMap[blogDetailEntityName]; hasEntitySettingMap {
			subPreloadFields, hasSubPreloadFields := preloadMap[blogDetailEntityName]
			subColumnMap, hasSubColumnMap := model.RepositoryPreloadMap[blogDetailRepositoryName]
			if hasSubPreloadFields && hasSubColumnMap {
				selectColMap := make(map[string]string)
				for _, field := range subPreloadFields {
					if _, exist := selectColMap[field]; !exist {
						if column, hasColumn := subColumnMap[field]; hasColumn {
							selectColMap[field] = column
						} else {
							selectColMap[field] = ""
						}
					}
				}
				var subSelectCols []string
				for _, column := range selectColMap {
					if column != "" {
						subSelectCols = append(subSelectCols, column)
					}
				}
				detailFilterMap := make(map[string]map[string][]any)
				detailFilterMap[model.BlogKnowledgeBaseDetailColumns.KnowledgeBaseID] = map[string][]any{
					"in": ids,
				}
				detailList, _, listErr := l.svcCtx.BlogBook.GetDetail(l.ctx, model.M{
					"select": strings.Join(subSelectCols, ","),
				}, -1, detailFilterMap) // 读取关联表
				if listErr != nil {
					return nil, listErr
				}

				if len(detailList) > 0 {
					for _, detail := range detailList {
						idDetailMap[detail.KnowledgeBaseID] = detail.PostContent
					}
				}
			}
		}

		for _, entry := range entryList {
			var categories []*blog.BlogCategory
			if terms, exist := idCategoryMap[entry.ID]; exist {
				categories = terms[:]
			}
			var tags []*blog.BlogTag
			if terms, exist := idTagMap[entry.ID]; exist {
				tags = terms[:]
			}
			var sections []*blog.BlogCategory
			if terms, exist := idSectionMap[entry.ID]; exist {
				sections = terms[:]
			}
			var media []*blog.BlogMedia
			if ms, exist := idMediaMap[entry.ID]; exist {
				media = ms[:]
			}
			var meta []*blog.BlogMeta
			if ms, exist := idMetaMap[entry.ID]; exist {
				meta = ms[:]
			}
			var es []*blog.BlogEntry
			if res, exist := idEntriesMap[entry.ID]; exist {
				es = res[:]
			}
			var score int32
			if res, exist := idStickyMap[entry.ID]; exist {
				score = int32(res) * enumx.BlogStickyTypeOffset
			}
			var contentHtml string
			if res, exist := idDetailMap[entry.ID]; exist {
				contentHtml = res
			}
			entries = append(entries, &blog.BookDetailResp{
				Id:            int64(entry.ID),
				ParentId:      int64(entry.PostParentID),
				Title:         entry.PostTitle,
				Excerpt:       entry.PostExcerpt,
				ContentHtml:   contentHtml,
				Status:        int32(entry.PostStatus),
				CommentStatus: int32(entry.CommentStatus),
				Slug:          entry.PostName,
				Uri:           entry.GUID,
				Date:          modelx.FormatTime(entry.PostDate, ""),
				DateGmt:       modelx.FormatTime(entry.PostDateGMT, ""),
				Modified:      modelx.FormatTime(entry.PostModifiedDate, ""),
				ModifiedGmt:   modelx.FormatTime(entry.PostModifiedGMT, ""),
				Order:         int64(entry.MenuOrder),
				CommentCount:  int32(entry.CommentCount),
				StickyScore:   score,
				Media:         media,
				Meta:          meta,
				Categories:    categories,
				Tags:          tags,
				Sections:      sections,
				Relations:     es,
			})
		}
	}

	var hasNextPage int32
	var hasPreviousPage int32
	if count > 1 {
		hasNextPage = 1
		count = count - 2
	}
	if count > 0 {
		hasPreviousPage = 1
	}
	return &blog.BookListResp{
		PageSize: int64(in.Limit),
		Data: entries,
		HasNextPage: hasNextPage,
		HasPreviousPage: hasPreviousPage,
		Offset: in.Offset + offset,
		SearchLogId: searchLogId,
	}, nil
}

func (l *BookListLogic) preFilterByTermId(
	filterMap map[string]map[string][]any,
	offset int32,
	limit int32,
) (oidMap map[uint64]int16, count int64, err error) {
	if limit == 0 {
		limit = int32(l.svcCtx.Config.Query.MaxAmount)
	}
	oidMap = make(map[uint64]int16) // Map: model.BlogTermRelationship.ObjectID => model.BlogTermRelationship.StickyType
	relationList, preCount, preErr := l.svcCtx.BlogTerm.GetRelationshipList(l.ctx, model.M{
		"offset":  offset,
		"limit":   limit,
		"orderBy": model.BlogTermRelationshipColumns.ObjectID + " DESC",
		"select":  model.BlogTermRelationshipColumns.ObjectID + "," + model.BlogTermRelationshipColumns.StickyType,
	}, 3, filterMap)
	if preErr != nil {
		err = preErr
		return
	}

	count = preCount
	if len(relationList) > 0 {
		for _, relationship := range relationList {
			if relationship.ObjectID == 0 {
				continue
			}

			if _, exist := oidMap[relationship.ObjectID]; !exist {
				oidMap[relationship.ObjectID] = relationship.StickyType
			}
		}
	}

	return
}

func (l *BookListLogic) filterByIds(
	filterMap map[string]map[string][]any,
	searchStr string,
	selectStr string,
) (list []*model.BlogKnowledgeBasis, err error) {
	list, _, err = l.svcCtx.BlogBook.GetList(l.ctx, model.M{
		"orderBy": model.BlogKnowledgeBasisColumns.ID + " DESC",
		"search":  searchStr,
		"select":  selectStr,
	}, -1, filterMap)
	return
}
